perm filename DESIGN.3[CLS,LSP] blob
sn#843903 filedate 1987-07-29 generic text, type T, neo UTF8
\input macros
\def\bookline{\CLOS\ Specification}
\def\chapline{Design Rationale}
\beginChapter 5.{Common Lisp Object System Specification}%
{Design Rationale}{Design Rationale}
\endTitlePage
\beginSection{Introduction}
This document contains design rationale for many of the decisions that
were made in the course of writing this proposal. The history behind
these design decisions should be useful to anyone evaluating this
proposal.
\endSection%{Introduction}
\beginSection{Why DEFMETHOD Disallows Method Selection on Optional Parameters}
Currently defmethod only allows required parameters to have specializers
and be used for method selection. It would be useful to extend
defmethod to allow optional and keyword parameters to be used for method
selection. (It does not seem useful to allow rest, supplied-p, or
auxiliary parameters to be used for method selection.) This extension
has not been included in the present standard because it raises
technical issues about defaulting, consistency among methods, and order
of evaluation of initforms. Discussion among the group has revealed
that these issues are not well enough understood yet to be appropriate
for standardization.
Note that the effect of using an optional or keyword parameter for
method selection, from the point of view of the caller of the generic
function, can be achieved by using the :interface option to defgeneric
to turn the optional or keyword parameter of the generic function into a
required parameter of the methods. Thus all defaulting and order of
evaluation issues are centralized within the defgeneric, at the cost of
requiring the writer of a method to specify a different parameter list.
\endSection%{Why DEFMETHOD Disallows Method Selection on Optional Parameters}
\beginSection{Motivation for Several DEFCLASS Defaults}
In designing DEFCLASS we followed the principle that the definer of a
class should be able to decide which parts of the class are strictly
internal, and which are intended as an external interface. This design
principle is a guideline that encourages good data abstraction.
Therefore, all DEFCLASS options that make a slot visible (such that its
value could be read, written, or initialized) are turned off by default.
The definer of a class needs to make an explicit decision to make a slot
visible externally, by specifying one or more options.
Along the same lines, the :accessor-prefix and :reader-prefix options do
not have a default for the prefix. This represents a departure from the
analogous defstruct :conc-name option, which does have a default, which
is the name of the structure followed by a hyphen.
If the definer of the class uses the :accessor-prefix or :reader-prefix
option, the slots are part of the external interface. There are several
reasonable conventions for naming slot accessors and readers. The definer
of the class might choose "" as the prefix, or the name of the class, a
more general component, or the name of a protocol followed by a hyphen.
Since no single possibility is clearly better than the others, we provide
no default prefix and leave the decision to the definer of the class.
\endSection%{Motivation for Several DEFCLASS Defaults}
\beginSection{Design Theories of the Integration of Types and Classes}
This section explains some of the design decisions regarding the
integration of the existing Common Lisp type system with the \CLOS\
class system. For background information, see the section
``Integrating Types and Classes''.
This section answers the following questions:
\beginlist
\item{\bull} Why do some of the standard Common Lisp types have a
corresponding class?
\item{\bull} Why don't all of the standard Common Lisp types have a
corresponding class?
\item{\bull} What were the guidelines for choosing which types would
have a class, and which would not?
\endlist
Question: Why do some of the standard Common Lisp types have a
corresponding class?
The purpose for specifying that many of the standard Common Lisp types
have a corresponding class is to allow users to write methods that
discriminate on these types; this is a powerful programming tool.
The standard type specifiers fit neatly into the method selection
model, but they are not suited to the complete \CLOS\ model, with respect
to building classes from superclasses, creating instances, and changing
the class of an instance. It is useful to discuss the practical and
conceptual distinctions between standard type classes and standard
classes. (A standard class is a user-defined class.) Standard type
classes have the following restrictions:
\beginlist
\item{\bull} A standard type class cannot be used as superclasses.
The difference between standard type classes and standard classes is
in the implementation of instances. Instances of a standard type class
are implemented in a specialized way that does not permit subclassing.
In some implementations some classes documented as standard type classes
might in fact be implemented as standard classes, but portable
programs cannot assume this.
\item{\bull} {\bf make-instance} cannot be used to create an instance
of a standard type class.
The capability of using {\bf make-instance} for standard type classes
gives no extra power or utility to the programmer. Also, the \CLOS\
model does not extend gracefully in this direction. Standard
classes have slots, but standard type classes have values of other
sorts (such as the value of an integer or the elements of an array)
which do not fit the {\bf make-instance} model.
\item{\bull} You cannot change the class of an instance of a standard
type class.
The semantics of changing an instance of a standard type class are not
at all clear. This is a basic difference between standard type
classes and standard classes.
\endlist
Question: Why don't all of the standard Common Lisp types have a
corresponding class?
It would be useful to extend the standard type classes to encompass the
full generality of Common Lisp type specifiers, but this raises
theoretical issues that are not yet appropriate for standardization.
These issues include:
\beginlist
\item{\bull} Deciding what to do when an argument is an instance of two
types, both of which have methods, but neither is a subtype of the
other. Some of the types in {\it Common Lisp: the Language\/}
have no constraints on their precedence relations to other types.
\item{\bull} The types that specify subranges present similar problems.
It is unclear how to determine the relative precedence of two
subranges of the same type.
\item{\bull} Dealing with Boolean combinations, such as negation, {\bf
and}, and {\bf or} presents problems with determinging relative
precedence order. For more information, see ``Boolean Classes'' by D.
McAllester and R. Zabih, a paper presented at the 1986 ACM First Annual
Conference on Object-Oriented Programming Systems, Languages, and
Applications.
\item{\bull} Some Common Lisp type specifiers are not defined clearly
enough in {\it Common Lisp: the Language\/} to be useful as classes.
Until the specification of these types is clarified, it would be
counterproductive to have corresponding classes for the types.
\item{\bull} Some types cannot be used for discrimination, such as {\bf
nil} and {\bf values}. No object can be an instance of these types
so there is no advantage to having classes for them.
\endlist
The \CLOS\ specification intentionally leaves room for adding more
standard type classes when these issues are resolved. For example,
when and if the Common Lisp Cleanup Committee provides a relative
precedence order on the types that currently lack them, these types
could have corresponding classes. Similarly, classes could be added
for the types whose specifications are currently too vague, whenever
the types are more rigorously defined.
Question: What were the guidelines for choosing which types would
have a class, and which would not?
The general guidelines were given above. The reasons for excluding
each individual type are given here:
{\it Boolean combinations and negation:\/}
{\bf and}
{\bf atom} - Negation {\bf (not cons}}.
{\bf or}
{\bf not}
{\it Subranges:\/}
{\bf bignum}
{\bf bit}
{\bf fixnum}
{\bf keyword}
{\bf member} - Subrange, if more than one argument is given.
{\bf mod} - Subrange of {\bf integer}.
{\bf satisfies} - Unclear subtype relations.
{\bf simple-array}
{\bf simple-bit-vector}
{\bf simple-string}
{\bf simple-vector}
{\bf standard-char}
{\bf string-char}
{\it The specification of these types is too vague:\/}
{\bf common}
{\bf stream}
{\bf function}
{\bf compiled-function}:
{\it No constraints on the precedence relations to other types:\/}
{\bf package}
{\bf readtable}
{\bf random-state}
{\bf hash-table}
{\bf pathname}
{\it No object can be an instance of this type:\/}
{\bf nil}
{\bf values}
{\it The meaning and existence of these types is
implementation-dependent:\/}
{\bf short-float}
{\bf long-float}
{\bf single-float}
{\bf double-float}
\endSection%{Design Theories of the Integration of Types and Classes}
\beginSection{Method Selection by Predications More General Than Classes}
This section should be considered a possible extension to the standard. It
is included in "Design Rationale" because it has been discussed in the
group.
The standard as currently proposed only allows method selection by the
classes of the arguments, or by equality to a given object, as in:
(QUOTE object). This could be extended in various ways. It is
important that any extensions to method selection remain consistent
with, and a subset of, Common Lisp type-specifiers, rather than
introducing a whole new type system in parallel with the existing one.
Method selection could be extended to allow the full generality of Common
Lisp type-specifiers; that is, arbitrary predications. The problem with
this is that there can be predications that have objects in common, but do
not have a subtype/supertype relationship. Thus if methods are defined for
both predications, it is not clear which method has precedence. This is in
contrast to classes; if an object is an instance of two classes, one class
is always a component of the other, and the subtype/supertype relationship
can always be determined.
Rather than totally ruling out method selection by predications because it
might not be clear which method has precedence, predications could be
allowed, with the requirement that an error is signalled if such a method
ambiguity is actually encountered. This would not prevent users from
defining a method on one predication, but would preclude defining methods
on two overlapping predications such as (integer 1 100) and (integer 50
144), which would signal an error if and only if the argument was an
integer between 50 and 100.
Subtype/supertype relationships can be computed for many of the most useful
predications, but in the most general case where this ordering is not
computable, the semantics are still well-defined, but not as amenable to
optimization. At run-time the value of the argument must be tested against
both predications. If both are true an error must be signalled, otherwise
the applicable method is well-defined. This extra testing of predications
can be minimized by converting the type-specifiers to canonical form. The
details are not given here because this is evidently an unexplored area
that is not yet appropriate for standardization.
\endSection%{Method Selection by Predications More General Than Classes}
\endChapter
\bye